package io.itit.ecp.admin.provide.action.controller.visualizing;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.common.enums.AIModelRunningModeEnums;
import io.itit.ecp.admin.common.enums.IMeterDeviceEnums;
import io.itit.ecp.admin.common.enums.MeterDeviceStaticsTypeEnums;
import io.itit.ecp.admin.provide.action.resp.AIModelResp;
import io.itit.ecp.admin.provide.action.resp.largescreen.RunningModeCompareResp;
import io.itit.ecp.admin.provide.action.resp.miniprogram.AiPredictionAccuracyResp;
import io.itit.ecp.admin.provide.action.resp.miniprogram.ElectricityPredictionRealityResp;
import io.itit.ecp.admin.provide.action.resp.miniprogram.PredictionRealityResp;
import io.itit.ecp.admin.provide.action.resp.miniprogram.RunningModeAnalysisResp;
import io.itit.ecp.admin.server.entity.*;
import io.itit.ecp.admin.server.service.IAIModelService;
import io.itit.ecp.admin.server.service.IRunningModeDataService;
import io.itit.ecp.admin.server.service.ISceneEdificeService;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.itit.grass.common.server.utils.ConvertUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 大屏统计-ai预测
 */
@Api(tags = "大屏统计-ai预测")
@RestController
@RequestMapping("/ecp-admin/largescreen/aiprediction")
@RequiredArgsConstructor
public class LargeScreenAiPredictionController {

    @Resource
    private IAIModelService aiModelService;

    @Resource
    private IRunningModeDataService runningModeDataService;

    @Resource
    private ISceneEdificeService sceneEdificeService;

    /**
     * ai预测-模型列表
     *
     * @param sceneProjectId sceneProjectId
     */
    @ApiOperation("ai预测-模型列表")
    @GetMapping("/model/list")
    public ResultResp<List<AIModelResp>> apModelList(@RequestParam(required = false) String sceneProjectId) {
        List<AIModelEntity> aiModel = aiModelService.lambdaQuery()
                .eq(StringUtils.hasLength(sceneProjectId), AIModelEntity::getSceneProjectId, sceneProjectId)
                .orderByDesc(AIModelEntity::getCreateTm)
                .list();
        return ResultResp.success(ConvertUtils.convert(aiModel, AIModelResp.class));
    }

    /**
     * ai预测-模型对比
     *
     * @param sceneProjectId sceneProjectId
     */
    @ApiOperation("ai预测-模型对比")
    @GetMapping("/modelcompare")
    public ResultResp<RunningModeCompareResp> modelCompare(@RequestParam(required = false) String sceneProjectId,
                                                           @RequestParam(required = false) String sceneEdificeId,
                                                           @RequestParam(required = false) String sceneFloorId,
                                                           @RequestParam(required = false) String sceneRoomId,
                                                           @RequestParam(required = false) String startTime,
                                                           @RequestParam(required = false) String endTime) {
        LocalDateTime start = StringUtils.hasLength(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = StringUtils.hasLength(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        List<RunningModeDataEntity> runningModeDataEntities = runningModeDataService.lambdaQuery()
                .eq(StringUtils.hasLength(sceneProjectId), RunningModeDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), RunningModeDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), RunningModeDataEntity::getSceneFloorId, sceneFloorId)
                .eq(StringUtils.hasLength(sceneRoomId), RunningModeDataEntity::getSceneRoomId, sceneRoomId)
                .ge(Objects.nonNull(start), RunningModeDataEntity::getSolidifyDate, start)
                .le(RunningModeDataEntity::getSolidifyDate, end)
                .list();
        String carbonValueUnit = "kgCO2";
        BigDecimal t = new BigDecimal("1000");
        RunningModeCompareResp resp = new RunningModeCompareResp();
        List<RunningModeCompareResp.RunningModeData> dataList = new ArrayList<>();
        List<RunningModeCompareResp.RunningModeTimeData> timeDataList = new ArrayList<>();
        for (AIModelRunningModeEnums runningMode : AIModelRunningModeEnums.values()) {
            List<RunningModeDataEntity> runningModelDataList = runningModeDataEntities.stream()
                    .filter(item -> Objects.equals(runningMode.getValue(), item.getRunningMode()))
                    .collect(Collectors.toList());
            RunningModeCompareResp.RunningModeData modeData = new RunningModeCompareResp.RunningModeData()
                    .setRunningMode(runningMode.getValue())
                    .setRunningModeName(runningMode.getLabel())
                    .setCarbonValue(runningModelDataList.stream().map(RunningModeDataEntity::getCarbonValue).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_DOWN))
                    .setIncomeValue(runningModelDataList.stream().map(RunningModeDataEntity::getIncomeValue).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_DOWN))
                    .setSaveElectricityCosts(runningModelDataList.stream().map(RunningModeDataEntity::getSaveElectricityCosts).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_DOWN));
            dataList.add(modeData);

            RunningModeCompareResp.RunningModeTimeData timeData = new RunningModeCompareResp.RunningModeTimeData()
                    .setRunningMode(runningMode.getValue())
                    .setRunningModeName(runningMode.getLabel())
                    .setTime(new BigDecimal(String.valueOf(runningModelDataList.size())).divide(new BigDecimal("4"), 2, RoundingMode.HALF_DOWN)); // 每4条为1小时的数据
            timeDataList.add(timeData);
        }
        if (dataList.stream().anyMatch(item -> item.getCarbonValue().compareTo(t) >= 0)) {
            carbonValueUnit = "tCO2";
            for (RunningModeCompareResp.RunningModeData runningModeData : dataList) {
                runningModeData.setCarbonValue(runningModeData.getCarbonValue().divide(t, 2, RoundingMode.HALF_DOWN));
            }
        }
        resp.setData(dataList);
        resp.setCarbonValueUnit(carbonValueUnit);
        resp.setDataTime(timeDataList);
        return ResultResp.success(resp);
    }

    /**
     * ai预测-模型分析
     *
     * @param sceneProjectId sceneProjectId
     * @param type           （1: 减排量，2: 费用，3：收益）
     */
    @ApiOperation("ai预测-模型分析")
    @GetMapping("/modelanalysis")
    public ResultResp<List<RunningModeAnalysisResp>> modelAnalysis(@RequestParam(required = false) String sceneProjectId,
                                                                   @RequestParam(required = false) String sceneEdificeId,
                                                                   @RequestParam(required = false) String sceneFloorId,
                                                                   @RequestParam(required = false) String sceneRoomId,
                                                                   @RequestParam String type,
                                                                   @RequestParam(required = false) String startTime,
                                                                   @RequestParam(required = false) String endTime) {
        LocalDateTime start = StringUtils.hasLength(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = StringUtils.hasLength(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        String unit = "kgCO2";
        BigDecimal t = new BigDecimal("1000");
        List<RunningModeDataEntity> runtimeDataList = Joins.of(RunningModeDataEntity.class)
                .select(RunningModeDataEntity::getCarbonValue,
                        RunningModeDataEntity::getIncomeValue,
                        RunningModeDataEntity::getSaveElectricityCosts,
                        RunningModeDataEntity::getSolidifyDate, RunningModeDataEntity::getRunningMode)
                .eq(StringUtils.hasLength(sceneProjectId), RunningModeDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), RunningModeDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), RunningModeDataEntity::getSceneFloorId, sceneFloorId)
                .eq(StringUtils.hasLength(sceneRoomId), RunningModeDataEntity::getSceneRoomId, sceneRoomId)
                .ge(Objects.nonNull(start), RunningModeDataEntity::getSolidifyDate, start)
                .le(RunningModeDataEntity::getSolidifyDate, end)
                .joinList(RunningModeDataEntity.class);
        List<RunningModeAnalysisResp> dataList = new ArrayList<>();
        Map<String, List<RunningModeDataEntity>> runningModeMap = runtimeDataList.stream()
                .collect(Collectors.groupingBy(RunningModeDataEntity::getRunningMode));
        for (AIModelRunningModeEnums modeEnums : AIModelRunningModeEnums.values()) {
            List<RunningModeDataEntity> modeDataEntityList = runningModeMap.getOrDefault(modeEnums.getValue(), Collections.emptyList());
            LinkedHashMap<String, List<RunningModeDataEntity>> solidifyDataMap = modeDataEntityList.stream()
                    .collect(Collectors.groupingBy(item -> DateUtil.format(item.getSolidifyDate(), "yyyy-MM-dd HH:00"), LinkedHashMap::new, Collectors.toList()));
            List<RunningModeAnalysisResp.DataItem> dataItems = new ArrayList<>();
            for (Map.Entry<String, List<RunningModeDataEntity>> entry : solidifyDataMap.entrySet()) {
                String date = entry.getKey();
                BigDecimal value = entry.getValue().stream().map(item -> {
                    if (org.apache.commons.lang3.StringUtils.equals(type, "1")) {
                        return item.getCarbonValue();
                    } else if (org.apache.commons.lang3.StringUtils.equals(type, "2")) {
                        return item.getIncomeValue();
                    } else if (org.apache.commons.lang3.StringUtils.equals(type, "3")) {
                        return item.getSaveElectricityCosts();
                    }
                    return BigDecimal.ZERO;
                }).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_DOWN);
                dataItems.add(new RunningModeAnalysisResp.DataItem().setTime(date).setValue(value));
            }
            RunningModeAnalysisResp analysisResp = new RunningModeAnalysisResp()
                    .setName(modeEnums.getLabel())
                    .setValue(modeEnums.getValue())
                    .setUnit(unit)
                    .setData(dataItems);
            dataList.add(analysisResp);
        }
        if (dataList.stream().anyMatch(item -> item.getData().stream().anyMatch(dataItem -> dataItem.getValue().compareTo(t) >= 0))) {
            unit = "tCO2";
            for (RunningModeAnalysisResp analysisResp : dataList) {
                analysisResp.setUnit(unit);
                for (RunningModeAnalysisResp.DataItem dataItem : analysisResp.getData()) {
                    dataItem.setValue(dataItem.getValue().divide(t, 2, RoundingMode.HALF_DOWN));
                }
            }
        }
        return ResultResp.success(dataList);
    }

    /**
     * ai预测-用电负荷预测与实际
     * Electricity load forecasting and actual situation
     *
     * @param sceneProjectId sceneProjectId
     */
    @ApiOperation("ai预测-用电负荷预测与实际")
    @GetMapping("/electricity/predictionreality")
    public ResultResp<List<ElectricityPredictionRealityResp>> electricityPredictionReality(@RequestParam String sceneProjectId,
                                                                                           @RequestParam(required = false) String sceneEdificeId,
                                                                                           @RequestParam(required = false) String sceneCompanyId,
                                                                                           @RequestParam(required = false) String sceneFloorId,
                                                                                           @RequestParam(required = false) String startTime,
                                                                                           @RequestParam(required = false) String endTime) {
        LocalDateTime start = StringUtils.hasLength(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = StringUtils.hasLength(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        String unit = "kwh";
        BigDecimal t = new BigDecimal("1000");
        List<EnergyDataEntity> energyDataEntities = Joins.of(EnergyDataEntity.class)
                .selectAs(builder -> builder.add("scene_edifice_id", "sceneEdificeId", false)
                        .add("SUM(meter_value)", "meterValue", false))
                .eq(EnergyDataEntity::getStaticsType, MeterDeviceStaticsTypeEnums.POWER_CONSUMPTION.getValue())
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneCompanyId), EnergyDataEntity::getSceneCompanyId, sceneCompanyId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(EnergyDataEntity::getSolidifyDate, end)
                .groupBy(EnergyDataEntity::getSolidifyDate)
                .orderByAsc(EnergyDataEntity::getSolidifyDate)
                .joinList(EnergyDataEntity.class);
        Map<String, BigDecimal> energyMeterValues = energyDataEntities.stream()
                .collect(Collectors.toMap(EnergyDataEntity::getSceneEdificeId, EnergyDataEntity::getMeterValue));

        List<EnergyForecastDataEntity> forecastDataList = Joins.of(EnergyForecastDataEntity.class)
                .selectAs(builder -> builder.add("scene_edifice_id", "sceneEdificeId", false)
                        .add("SUM(meter_forecast_value)", "meterForecastValue", false))
                .eq(StringUtils.hasLength(sceneProjectId), EnergyForecastDataEntity::getSceneProjectId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyForecastDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneCompanyId), EnergyForecastDataEntity::getSceneCompanyId, sceneCompanyId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyForecastDataEntity::getSceneFloorId, sceneFloorId)
                .ge(Objects.nonNull(start), EnergyForecastDataEntity::getSolidifyDate, start)
                .le(EnergyForecastDataEntity::getSolidifyDate, end)
                .eq(EnergyForecastDataEntity::getStaticsType, MeterDeviceStaticsTypeEnums.POWER_CONSUMPTION.getValue())
                .groupBy(EnergyForecastDataEntity::getSolidifyDate)
                .joinList(EnergyForecastDataEntity.class);
        Map<String, BigDecimal> forecastDataTimeValueMap = forecastDataList.stream()
                .collect(Collectors.toMap(EnergyForecastDataEntity::getSceneEdificeId, EnergyForecastDataEntity::getMeterForecastValue));

        List<SceneEdificeEntity> edificeEntities = sceneEdificeService.lambdaQuery()
                .eq(SceneEdificeEntity::getSceneProjectId, sceneProjectId)
                .orderByAsc(SceneEdificeEntity::getEdificeName)
                .list();

        List<String> edificeNames = edificeEntities.stream().map(SceneEdificeEntity::getEdificeName).collect(Collectors.toList());
        List<ElectricityPredictionRealityResp> list = new ArrayList<>();
        list.add(new ElectricityPredictionRealityResp()
                .setName("实际")
                .setUnit(unit)
                .setEdificeNames(edificeNames)
                .setValue(edificeEntities.stream()
                        .map(item -> energyMeterValues.getOrDefault(item.getId(), BigDecimal.ZERO).setScale(2, RoundingMode.HALF_DOWN))
                        .collect(Collectors.toList()))
        );

        list.add(new ElectricityPredictionRealityResp()
                .setName("预测")
                .setUnit(unit)
                .setType("line")
                .setEdificeNames(edificeNames)
                .setValue(edificeEntities.stream()
                        .map(item -> forecastDataTimeValueMap.getOrDefault(item.getId(), BigDecimal.ZERO).setScale(2, RoundingMode.HALF_DOWN))
                        .collect(Collectors.toList()))
        );
        if (list.stream().anyMatch(item -> item.getValue().stream().anyMatch(value -> value.compareTo(t) >= 0))) {
            unit = "MWh";
            for (ElectricityPredictionRealityResp predictionRealityResp : list) {
                predictionRealityResp.setUnit(unit);
                predictionRealityResp.setValue(predictionRealityResp.getValue().stream()
                        .map(item -> item.divide(t, 2, RoundingMode.HALF_UP)).collect(Collectors.toList()));
            }
        }
        return ResultResp.success(list);
    }

    /**
     * 光伏发电预测与实际
     */
    @ApiOperation("光伏发电预测与实际")
    @GetMapping("powergeneration/predictionreality")
    public ResultResp<List<PredictionRealityResp>> powerGenerationPredictionReality(@RequestParam(required = false) String sceneProjectId,
                                                                                    @RequestParam(required = false) String sceneEdificeId,
                                                                                    @RequestParam(required = false) String sceneCompanyId,
                                                                                    @RequestParam(required = false) String sceneFloorId,
                                                                                    @RequestParam(required = false) String startTime,
                                                                                    @RequestParam(required = false) String endTime) {
        LocalDateTime start = StringUtils.hasLength(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = StringUtils.hasLength(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        String unit = "kwh";
        BigDecimal t = new BigDecimal("1000");
        List<EnergyDataEntity> energyDataEntities = Joins.of(EnergyDataEntity.class)
                .selectAs(builder -> builder.add("DATE_FORMAT(solidify_date,'%Y-%m-%d %H:%m')", "deviceCode", false)
                        .add("SUM(meter_value)", "meterValue", false))
                .eq(EnergyDataEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.readMeterType11.getValue())
                .eq(EnergyDataEntity::getStaticsType, MeterDeviceStaticsTypeEnums.POWER_GENERATION.getValue())
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneCompanyId), EnergyDataEntity::getSceneCompanyId, sceneCompanyId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(EnergyDataEntity::getSolidifyDate, end)
                .groupBy(EnergyDataEntity::getSolidifyDate)
                .orderByAsc(EnergyDataEntity::getSolidifyDate)
                .joinList(EnergyDataEntity.class);
        Map<String, BigDecimal> timeValuesMap = energyDataEntities.stream()
                .collect(Collectors.toMap(EnergyDataEntity::getDeviceCode, EnergyDataEntity::getMeterValue));

        List<EnergyForecastDataEntity> forecastDataList = Joins.of(EnergyForecastDataEntity.class)
                .selectAs(builder -> builder.add("DATE_FORMAT(solidify_date,'%Y-%m-%d %H:%m')", "deviceCode", false)
                        .add("SUM(meter_forecast_value)", "meterForecastValue", false))
                .eq(StringUtils.hasLength(sceneProjectId), EnergyForecastDataEntity::getSceneProjectId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyForecastDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneCompanyId), EnergyForecastDataEntity::getSceneCompanyId, sceneCompanyId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyForecastDataEntity::getSceneFloorId, sceneFloorId)
                .eq(EnergyForecastDataEntity::getStaticsType, MeterDeviceStaticsTypeEnums.POWER_GENERATION.getValue())
                .ge(Objects.nonNull(start), EnergyForecastDataEntity::getSolidifyDate, start)
                .le(EnergyForecastDataEntity::getSolidifyDate, end)
                .groupBy(EnergyForecastDataEntity::getSolidifyDate)
                .joinList(EnergyForecastDataEntity.class);
        Map<String, BigDecimal> forecastDataTimeValueMap = forecastDataList.stream()
                .collect(Collectors.toMap(EnergyForecastDataEntity::getDeviceCode, EnergyForecastDataEntity::getMeterForecastValue));

        List<String> times = CollectionUtil.union(timeValuesMap.keySet(), forecastDataTimeValueMap.keySet()).stream().sorted().collect(Collectors.toList());

        List<PredictionRealityResp> list = new ArrayList<>();
        list.add(new PredictionRealityResp()
                .setName("实际")
                .setUnit(unit)
                .setTime(times)
                .setValue(times.stream()
                        .map(item -> timeValuesMap.getOrDefault(item, BigDecimal.ZERO).setScale(2, RoundingMode.HALF_DOWN))
                        .collect(Collectors.toList()))
        );

        list.add(new PredictionRealityResp()
                .setName("预测")
                .setUnit(unit)
                .setType("line")
                .setTime(times)
                .setValue(times.stream()
                        .map(item -> forecastDataTimeValueMap.getOrDefault(item, BigDecimal.ZERO).setScale(2, RoundingMode.HALF_DOWN))
                        .collect(Collectors.toList()))
        );
        if (list.stream().anyMatch(item -> item.getValue().stream().anyMatch(value -> value.compareTo(t) >= 0))) {
            unit = "MWh";
            for (PredictionRealityResp predictionRealityResp : list) {
                predictionRealityResp.setUnit(unit);
                predictionRealityResp.setValue(predictionRealityResp.getValue().stream().map(item -> item.divide(t, 2, RoundingMode.HALF_DOWN)).collect(Collectors.toList()));
            }
        }
        return ResultResp.success(list);
    }

    /**
     * 预测精度
     */
    @GetMapping("accuracy")
    @ApiOperation("预测精度")
    public ResultResp<List<AiPredictionAccuracyResp>> accuracy(@RequestParam(required = false) String sceneProjectId,
                                                               @RequestParam(required = false) String sceneEdificeId,
                                                               @RequestParam(required = false) String sceneCompanyId,
                                                               @RequestParam(required = false) String sceneFloorId,
                                                               @RequestParam(required = false) String startTime,
                                                               @RequestParam(required = false) String endTime) {

        LocalDateTime start = StringUtils.hasLength(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = StringUtils.hasLength(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        List<EnergyForecastDataEntity> staticsTypeList = Joins.of(EnergyForecastDataEntity.class)
                .selectAs(builder -> builder.add("statics_type", "staticsType", false)
                        .add("SUM(forecast_precision)", "forecastPrecision", false))
                .eq(StringUtils.hasLength(sceneProjectId), EnergyForecastDataEntity::getSceneProjectId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyForecastDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneCompanyId), EnergyForecastDataEntity::getSceneCompanyId, sceneCompanyId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyForecastDataEntity::getSceneFloorId, sceneFloorId)
                .ge(Objects.nonNull(start), EnergyForecastDataEntity::getSolidifyDate, start)
                .le(EnergyForecastDataEntity::getSolidifyDate, end)
                .groupBy(EnergyForecastDataEntity::getStaticsType)
                .joinList(EnergyForecastDataEntity.class);
        List<AiPredictionAccuracyResp> list = new ArrayList<>();
        list.add(new AiPredictionAccuracyResp().setName("用电量")
                .setValue(staticsTypeList.stream()
                        .filter(item -> StringUtils.pathEquals(item.getStaticsType(), MeterDeviceStaticsTypeEnums.POWER_CONSUMPTION.getValue()))
                        .map(EnergyForecastDataEntity::getForecastPrecision).findFirst().orElse(BigDecimal.ZERO).setScale(2, RoundingMode.HALF_DOWN))
                .setPreValue(BigDecimal.ZERO) // TODO: 同比值/同比率/环比值/环比率：待定
                .setMValue(BigDecimal.ZERO)
                .setMRate(BigDecimal.ZERO));
        list.add(new AiPredictionAccuracyResp().setName("发电量")
                .setValue(staticsTypeList.stream()
                        .filter(item -> StringUtils.pathEquals(item.getStaticsType(), MeterDeviceStaticsTypeEnums.POWER_GENERATION.getValue()))
                        .map(EnergyForecastDataEntity::getForecastPrecision).findFirst().orElse(BigDecimal.ZERO).setScale(2, RoundingMode.HALF_DOWN))
                .setPreValue(BigDecimal.ZERO) // TODO: 同比值/同比率/环比值/环比率：待定
                .setMValue(BigDecimal.ZERO)
                .setMRate(BigDecimal.ZERO));
        return ResultResp.success(list);
    }

}
